//--Yangxin--

`include "defines.v"
module cpu_axi_interface(
    input   wire clk                  ,
    input   wire reset                ,

    //inst sram-like,
    input   wire         inst_req     ,
    input   wire         inst_wr      ,
    input   wire  [ 2:0] inst_size    ,
    input   wire  [63:0] inst_addr    , 
    input   wire  [63:0] inst_wdata   ,
    output  wire  [63:0] inst_rdata   ,
    output  wire         inst_addr_ok ,
    output  wire         inst_data_ok ,
    //data sram-like
    input   wire         data_req     ,    
    input   wire         data_wr      ,
    input   wire  [ 2:0] data_size    ,
    input   wire  [63:0] data_addr    ,
    input   wire  [63:0] data_wdata   ,
    output  wire  [63:0] data_rdata   ,
    output  wire         data_addr_ok ,
    output  wire         data_data_ok ,

    //axi
    //ar
    output  wire  [ 3:0] arid         ,
    output  wire  [63:0] araddr       ,
    output  wire  [ 7:0] arlen        ,
    output  wire  [ 2:0] arsize       ,
    output  wire  [ 1:0] arburst      ,
    output  wire  [ 1:0] arlock       ,   //weikuan
    output  wire  [ 3:0] arcache      ,
    output  wire  [ 2:0] arprot       ,
    output  wire         aruser       ,
    output  wire  [ 3:0] arqos        ,
    output  wire  [ 3:0] arregion     ,
    output  wire         arvalid      ,
    input   wire         arready      ,
    //r
    input   wire  [ 3:0] rid          ,
    input   wire         ruser        ,
    input   wire  [63:0] rdata        ,
    input   wire  [ 1:0] rresp        ,
    input   wire         rlast        ,
    input   wire         rvalid       ,
    output  wire         rready       ,
    //aw
    output  wire  [ 3:0] awid         ,
    output  wire  [63:0] awaddr       ,
    output  wire  [ 7:0] awlen        ,
    output  wire  [ 2:0] awsize       ,
    output  wire  [ 1:0] awburst      ,
    output  wire  [ 1:0] awlock       ,
    output  wire  [ 3:0] awcache      ,
    output  wire  [ 2:0] awprot       ,
    output  wire         awuser       ,
    output  wire         awqos        ,
    output  wire         awregion     ,
    output  wire         awvalid      ,
    input   wire         awready      ,
    //w
    //output  wire  [ 3:0] wid        ,
    output  wire         wuser        ,
    output  wire  [63:0] wdata        ,
    output  wire  [ 7:0] wstrb        ,
    output  wire         wlast        ,
    output  wire         wvalid       ,
    input   wire         wready       ,
    //b
    input   wire  [ 3:0] bid          ,
    input   wire         buser        ,
    input   wire  [ 1:0] bresp        ,
    input   wire         bvalid       ,
    output  wire         bready
);



//addr
reg        do_req    ;
reg        do_req_or ;  //req is inst or data;1:data;0:inst
reg        do_wr_r   ;
reg [ 2:0] do_size_r ;
reg [63:0] do_addr_r ;
reg [63:0] do_wdata_r;

reg [63:0] do_addr_r_w;

wire   data_back;
assign inst_addr_ok = !do_req && !data_req;
assign data_addr_ok = !do_req;

always @(posedge clk) begin
    do_req     <= reset                             ? 1'b0 :
                  (inst_req || data_req) && !do_req ? 1'b1 :
                  data_back                         ? 1'b0 : do_req;

    do_req_or  <= reset ? 1'b0:
                  !do_req ? data_req : do_req_or;

    do_wr_r    <= reset                    ? 1'b0    :
                  data_req && data_addr_ok ? data_wr :
                  inst_req && inst_addr_ok ? inst_wr : do_wr_r;

    do_size_r  <= reset                    ? 3'b00     :
                  data_req && data_addr_ok ? data_size :
                  inst_req && inst_addr_ok ? inst_size : do_size_r;

    do_addr_r  <= reset                    ? 64'h0     :
                  data_req && data_addr_ok ? data_addr :
                  inst_req && inst_addr_ok ? inst_addr : do_addr_r;
    // do_addr_r_w<= reset                    ? 64'h0     :
    //               data_req && data_addr_ok ? {data_addr[63:2],2'b0} :
    //               inst_req && inst_addr_ok ? inst_addr : do_addr_r;

    do_wdata_r <= reset                    ? 64'h0      :
                  data_req && data_addr_ok ? data_wdata :
                  inst_req && inst_addr_ok ? inst_wdata : do_wdata_r;
end 

//inst sram-like
assign inst_data_ok = do_req && !do_req_or && data_back;
assign data_data_ok = do_req &&  do_req_or && data_back;
assign inst_rdata   = (araddr[2] == 1'b0) ? {32'h0,rdata[31:0]} :
                                            {32'h0,rdata[63:32]};
assign data_rdata   = rdata;

//axi
reg addr_rcv;
reg wdata_rcv;

assign data_back = addr_rcv && (rvalid && rready || bvalid && bready);

always @(posedge clk) begin
    addr_rcv <= reset                ? 1'b0:
                (arvalid && arready) ? 1'b1:
                (awvalid && awready) ? 1'b1:
                data_back            ? 1'b0: addr_rcv;

    wdata_rcv <= reset            ? 1'b0:
                 wvalid && wready ? 1'b1:
                 data_back        ? 1'b0: wdata_rcv;
end

// reg addr_rcv_d1;
// always @(posedge clk) begin
//     addr_rcv_d1 <= addr_rcv;
// end

//ar
assign arid     = 4'd0                           ;
assign araddr   = do_addr_r                      ;
//assign araddr   = {do_addr_r[63:2],2'b0}         ;
assign arlen    = 8'd0                           ;
//assign arsize   = do_size_r                      ;
assign arsize   = araddr[31] ?  2'd3 : 2'd2                      ;
assign arburst  = 2'd1                           ;
assign arlock   = 2'd0                           ;
assign arcache  = 4'd0                           ;
assign arprot   = 3'd0                           ;
assign aruser   = 1'b0                           ;
assign arqos    = 4'b0                           ;
assign arregion = 4'b0                           ;
assign arvalid  = do_req && !do_wr_r && !addr_rcv;
//r
assign rready  = 1'b1                            ;

//aw
assign awid     = 4'd0                           ;
assign awaddr   = do_addr_r                      ;
//assign awaddr   = {do_addr_r[63:2],2'b0}         ;
assign awlen    = 8'd0                           ;
assign awsize   = awaddr[31] ? 2'd3 : 2'd2                      ;  //11.27
//assign awsize   = 2'd3                      ;   //11.27(2'd3)
assign awburst  = 2'd1                           ;
assign awlock   = 2'd0                           ;
assign awcache  = 4'd0                           ;
assign awprot   = 3'd0                           ;
assign awuser   = 1'b0                           ;
assign awqos    = 4'b0                           ;
assign awregion = 4'b0                           ;
assign awvalid  = do_req && do_wr_r && !addr_rcv ;
//w
//assign wid     = 4'd0                         ;
assign wdata   = do_wdata_r                     ;
assign wstrb   = (do_size_r[1:0] == 2'b00) ? 8'b0000_0001<<do_addr_r[2:0] :
                 (do_size_r[1:0] == 2'b01) ? 8'b0000_0011<<{do_addr_r[2:1],1'b0} :
                 (do_size_r[1:0] == 2'b10) ? 8'b0000_1111<<{do_addr_r[2],2'b0}   :
                 (do_size_r[1:0] == 2'd11) ? 8'b1111_1111                 :
                                             8'b1111_1111                 ;
// assign wstrb   = (do_size_r[2:1] == 2'b00) ? 8'b0000_0001 :
//                  (do_size_r[2:1] == 2'b01) ? 8'b0000_0011<<do_addr_r[2:1] :
//                  (do_size_r[2:1] == 2'b10) ? 8'd0000_1111<<do_addr_r[2]   :
//                  (do_size_r[2:1] == 2'd11) ? 8'd1111_1111                 :
//                                       8'd1111_1111                   ;
assign wlast   = 1'b1;
assign wvalid  = do_req && do_wr_r && !wdata_rcv;
assign wuser   = 1'b0                           ;
//b
assign bready = 1'b1;

endmodule